home *** CD-ROM | disk | FTP | other *** search
Wrap
/* Pop Up Menu CDEF.c */ /* */ /* By: */ /* Chris Faigle */ /* */ /* With ideas, code, bug fixes, testing, time, and effort by: */ /* Rick Aurbach */ /* Pete Deignan */ /* Joe Schwartz */ /* Mike Puckett */ /* Steve Hutcherson */ /* Doug McKenna */ /* Jerry Shields */ /* Ton Mommers */ /* Christoph Sold */ /* Robert Mah */ /* Tom Becker */ /* and others.. */ /* */ /* */ /* Version 1.4 Final */ /* September, 1990 */ /* */ /* */ /* This software is now in the Public Domain, providing the following: */ /* No fee other than normal copying or bulletin-board time fees */ /* may be charged for this software. The CDEF may be included in */ /* commercial software without fees or notices. Portions of the */ /* CDEF are copyright Symantec Corp. */ /* */ /* If you make enhancements to this software, PLEASE send me a copy! */ /* */ /* Address any correspondence/bug reports/suggestions to: */ /* Chris Faigle */ /* c/o Performance Software */ /* 575 SouthLake Blvd */ /* Richmond, VA 23236 */ /* AppleLink: CHRIS.FAIGLE */ /* */ /* Please Read ‘Pop Up Menu CDEF Instructions’ for more info */ /* */ #include "ControlMgr.h" #include "SetUpA4.h" #define LEFT_SPACE 15 /* Changed from 13 1.4b3 */ #define IN_MENU 1 #define INACTIVE 255 #define LOW_31_BITS_MASK 0x7FFFFFFF #define CODE_MASK 0x000F #define HI_BYTE 0xFF00 #define LO_BYTE 0x00FF #define TITLED_MASK 0x0001 #define NEW_STYLE_MASK 0x0002 #define CHECK_MASK 0x0004 #define EXTRA_SPACE_FOR_NEW_STYLE 13 #define SICN_SPACE 20 #define RICN_SPACE 20 #define ICON_SPACE 36 #define RICN_MENU 29 #define SICN_MENU 30 #define NORMAL_MENU_SIZE 16 #define RICN_MENU_SIZE 20 #define SICN_MENU_SIZE 20 #define ICON_MENU_SIZE 36 typedef short SICN[16]; /* This info is in Tech Note #252: */ typedef SICN *SICNList; /* “Plotting Small Icons” */ typedef SICNList *SICNHand; typedef struct { short type; short we_loaded_the_menu; MenuHandle the_menu; } pop_up_data_struct,**pop_up_data_handle; typedef struct { short save_size; short save_font; Style save_face; PenState save_pen; } pen_font_struct,**pen_font_handle; #ifndef calcCntlRgn #define calcCntlRgn 10 #endif #ifndef calcThumbRgn #define calcThumbRgn 11 #endif #ifndef NULL #define NULL 0l #endif /* Declare function return values: */ long draw_control(); long test_control(); long calculate_control_region(); long initialize_control(); long dispose_control(); long position_control(); long thumb_control(); long drag_control(); long auto_track_control(); MenuHandle get_pop_menu(); short calculate_retangles(); short draw_pop_up_symbol(); short save_pen_font(); short set_pen_font(); short gray_out_rectangle(); short plot_sicn(); void shrink_string(); pascal void new_calc_menu_size(); short trap_calc_menu_size(); void convert_rectangle(); short check_color(); /* Declare our trap address global variables */ void (*real_calc_menu_size)(); short pop_up_menu_width; pascal long main(short code,ControlHandle the_control,short message,long parameter) { long return_value; short control_type; pen_font_struct save_struct; short the_id; long the_type; Str255 the_name; RememberA0(); SetUpA4(); HLock(the_control); /* Lock the control handle */ save_pen_font(the_control,&save_struct); /* Save off the pen, font, style */ GetResInfo(the_control,&the_id,&the_type,&the_name); if(ResError()!=resNotFound) { SysBeep(1); } control_type=BitAnd(code,CODE_MASK); /* Find out type 0=No Title 1=Title */ switch(message) /* Which Message were we sent?? */ { case drawCntl: adjust_max_and_min(the_control); /* First, adjust the Max and Min Values */ return_value=draw_control(control_type,the_control,parameter); break; case testCntl: return_value=test_control(control_type,the_control,parameter); break; case calcCRgns: parameter&=LOW_31_BITS_MASK; /* Strip off High Bit */ case calcCntlRgn: case calcThumbRgn: return_value=calculate_control_region(control_type,the_control,parameter); break; case initCntl: return_value=initialize_control(control_type,the_control,parameter); break; case dispCntl: return_value=dispose_control(control_type,the_control,parameter); break; case posCntl: return_value=position_control(control_type,the_control,parameter); break; case thumbCntl: return_value=thumb_control(control_type,the_control,parameter); break; case dragCntl: return_value=drag_control(control_type,the_control,parameter); break; case autoTrack: return_value=auto_track_control(control_type,the_control,parameter); break; } set_pen_font(&save_struct); /* Restore the pen, font, style */ HUnlock(the_control); /* Unlock the control handle */ RestoreA4(); return(return_value); } long draw_control(short control_type,ControlHandle the_control,long parameter) { Str255 current_selection_text; /* Text of the current menu item */ Rect control_rectangle; /* Rectangle of the actual menu item */ Rect title_rect; /* Rectangle containing the title if any */ FontInfo font_info; /* Font info of the current font */ Point text_point; /* The point where we draw the text */ short titled; /* Does this control have a title? */ short new_style; /* Is is a new style pop up? */ short ball_check_char; /* Should we use the '•' as a check character */ short use_window_font; /* Should we use the window's font for the title? */ short active; /* Is this control active? */ short visible; /* Is this control visible? */ MenuHandle the_menu; /* The control's menu */ short command_char; /* This is used to determine if there is a ricn, sicn, etc. */ short which_sicn; /* The sicn if it exists */ short which_icon; /* The icon if it exists */ Rect icon_rect; /* The rectangle to plot the icon in */ Handle icon_handle; /* The handle to the Icon */ short space_on_left; /* The space to the left of the menu item */ short item_style; /* Text Face of the Item */ short color_qd_implemented; /* Is Color QuickDraw Implemented? */ MCEntryPtr item_color_ptr; /* The colors of the menu item */ RGBColor background_color; /* Current background color */ RGBColor foreground_color; /* Current foreground color */ short space_for_string; /* Space available for item string */ short have_item_color=FALSE; /* Do we need to set color values for this item */ RGBColor item_foreground_color; /* Items foreground color */ RGBColor item_background_color; /* Item's background color */ short has_enough_pixel_depth; /* Used in determining if we have enough depth to support color */ Point conversion_point; /* Used in converting Local to Global to Local */ Rect intersection_rect; /* Dummy rectangle used in SecRect */ GDHandle check_device; /* Graphics device we are checking for pixel depth */ titled=control_type&TITLED_MASK; /* Is there a title? */ new_style=control_type&NEW_STYLE_MASK; /* Is it the New Style? */ color_qd_implemented=check_color(); space_on_left=LEFT_SPACE; /* Use the normal amount of space on the left (1.4b2) */ ball_check_char=control_type&CHECK_MASK; /* Use the '•' check char? */ use_window_font=control_type&useWFont; /* Use the Window's Font? */ if((**the_control).contrlHilite==INACTIVE) /* Is the control inactive?? */ { active=FALSE; /* Yes - set active flag to FALSE */ } else /* No - set active flag to TRUE */ { active=TRUE; } visible=(**the_control).contrlVis; /* Store visibility state */ if(visible) /* if Invisible DO NOT Draw */ { PenNormal(); /* Set the Pen to: 1x1, PatCopy & black */ the_menu=get_pop_menu(the_control); /* Get the MenuHandle */ if(the_menu==NULL) /* Did we get a valid Menu Handle */ { current_selection_text[0]='\0'; /* No - Then no selection Text */ item_style=0; /* No Style */ } else { GetItemStyle(the_menu,(**the_control).contrlValue,&item_style); /* Yes-Get the style of the menu Item */ GetItem(the_menu,(**the_control).contrlValue,¤t_selection_text); /* Get the Text of the current selection */ } calculate_rectangles(the_control,titled,new_style,use_window_font,&title_rect,&control_rectangle); if(titled) /* Is it a Titled Pop Up Window?? */ { GetFontInfo(&font_info); /* Get Font Info */ text_point.v=(title_rect.top+title_rect.bottom+font_info.ascent-font_info.descent)/2; text_point.h=title_rect.left+1; MoveTo(text_point.h,text_point.v); /* Move to where title is drawn */ DrawString((**the_control).contrlTitle);/* Draw the Title */ } TextFont(systemFont); /* Use System Font for Menus */ TextSize(0); /* Use System Size */ TextFace(0); /* Use No Style */ convert_rectangle(&control_rectangle,TRUE); has_enough_pixel_depth=TRUE; if(color_qd_implemented&&(the_menu!=NULL)) /* Do we have color? (Bug Fix 1.4 Final) */ { if(has_enough_pixel_depth) /* Did we have enough pixel depth for color? */ { GetBackColor(&background_color); /* Save the current background color */ GetForeColor(&foreground_color); /* Save the current foreground color */ item_color_ptr=NULL; /* Start the pointer at NULL */ item_color_ptr=GetMCEntry((**the_menu).menuID,(**the_control).contrlValue); /* Get the item's color table */ if(item_color_ptr!=NULL) { have_item_color=TRUE; /* Store a flag that we have color for this item */ BlockMove(&item_color_ptr->mctRGB2,&item_foreground_color,sizeof(RGBColor));/* Copy the table, since it is relocatable */ BlockMove(&item_color_ptr->mctRGB4,&item_background_color,sizeof(RGBColor));/* Copy the table, since it is relocatable */ RGBBackColor(&item_background_color); /* Use item's background color as backgound color for popup */ } else /* This item does not have an individual color entry */ { item_color_ptr=GetMCEntry(0,0); /* So get the system menu color table */ if(item_color_ptr!=NULL) /* Did we get it? */ { BlockMove(&item_color_ptr->mctRGB3,&item_foreground_color,sizeof(RGBColor));/* Copy the table, since it is relocatable */ BlockMove(&item_color_ptr->mctRGB2,&item_background_color,sizeof(RGBColor));/* Copy the table, since it is relocatable */ RGBBackColor(&item_background_color); /* Use item's background color as backgound color for popup */ have_item_color=TRUE; /* Store a flag that we have color for this item */ } else /* Nope. We could not get the system menu color table */ { have_item_color=FALSE; /* Store a flag that we do not have color for this item */ } } } } convert_rectangle(&control_rectangle,FALSE); InsetRect(&control_rectangle,-1,-1); /* Make the Rectangle a hare larger */ EraseRect(&control_rectangle); /* Erase the Rectangle */ FrameRect(&control_rectangle); /* Frame it */ space_for_string=control_rectangle.right-control_rectangle.left-space_on_left; if(active) /* Inactive controls have no drop shadow */ { MoveTo(control_rectangle.right,control_rectangle.top+2); /* Draw its Shadow */ LineTo(control_rectangle.right,control_rectangle.bottom); LineTo(control_rectangle.left+2,control_rectangle.bottom); } if(new_style) /* If new style, draw the extra down arrow on the right */ { draw_pop_up_symbol(control_rectangle.right-10,(control_rectangle.bottom+control_rectangle.top)/2-3); space_for_string-=10; } GetFontInfo(&font_info); /* Get Font Info (for system font) */ if(color_qd_implemented&&have_item_color) { RGBForeColor(&item_foreground_color); /* Use the foreground color as the color for the menu item */ } if(the_menu!=NULL) { GetItemCmd(the_menu,(**the_control).contrlValue,&command_char); /* NOTE: command_char is actually an int (short for MPW C), not a char Inside Mac V-240 is incorrect! */ switch(command_char) { case SICN_MENU: GetItemIcon(the_menu,(**the_control).contrlValue,&which_sicn); if(color_qd_implemented&&((icon_handle=(Handle)GetCIcon(which_sicn+256))!=NULL)) /* NOTE: This is here only because under Color QD, the menu Manager looks */ { /* for a cicn before looking for a sicn, even though you specified a sicn! Bug? */ icon_rect.left=control_rectangle.left+space_on_left; /* +2 removed 1.4b3 */ /* Calculate the rectangle to plot the CICN in (as a reduced CICN!) */ icon_rect.right=icon_rect.left+16; icon_rect.top=(control_rectangle.bottom+control_rectangle.top-16)/2; /* -1 rmvd 1.4b3 *//* Calculate middle of control (the -1 is new in 1.3.1) */ icon_rect.bottom=icon_rect.top+16; PlotCIcon(&icon_rect,icon_handle); DisposCIcon(icon_handle); } else { plot_sicn(the_control,control_rectangle.left+space_on_left,control_rectangle.top+3,which_sicn); /* +2 removed 1.4b3 */ } MoveTo(control_rectangle.left+space_on_left+SICN_SPACE,(control_rectangle.top+control_rectangle.bottom+font_info.ascent-font_info.descent)/2);/* Move to where Text should be drawn */ space_for_string-=SICN_SPACE; break; case RICN_MENU: GetItemIcon(the_menu,(**the_control).contrlValue,&which_icon); icon_rect.left=control_rectangle.left+space_on_left; /* +2 removed 1.4b3 */ icon_rect.right=icon_rect.left+16; icon_rect.top=(control_rectangle.bottom+control_rectangle.top-16)/2; icon_rect.bottom=icon_rect.top+16; if(color_qd_implemented&&((icon_handle=(Handle)GetCIcon(which_icon+256))!=NULL)) { PlotCIcon(&icon_rect,icon_handle); DisposCIcon(icon_handle); } else /* If no cicn, try for a normal Icon resource */ { icon_handle=GetResource('ICON',which_icon+256); if(icon_handle!=NULL) { PlotIcon(&icon_rect,icon_handle); } } MoveTo(control_rectangle.left+space_on_left+RICN_SPACE,(control_rectangle.top+control_rectangle.bottom+font_info.ascent-font_info.descent)/2);/* Move to where Text should be drawn */ space_for_string-=RICN_SPACE; break; default: GetItemIcon(the_menu,(**the_control).contrlValue,&which_icon); if(which_icon==0) { /* We have no Icon, Sicn, or reduced Icon in the Menu */ MoveTo(control_rectangle.left+space_on_left,(control_rectangle.top+control_rectangle.bottom+font_info.ascent-font_info.descent)/2);/* Move to where Text should be drawn */ } else { /* We have an Icon in the Menu */ icon_rect.left=control_rectangle.left+space_on_left; /* +2 removed 1.4b3 */ icon_rect.right=icon_rect.left+32; icon_rect.top=(control_rectangle.bottom+control_rectangle.top-32)/2; icon_rect.bottom=icon_rect.top+32; if(color_qd_implemented&&((icon_handle=(Handle)GetCIcon(which_icon+256))!=NULL)) /* Do we have Color QD and a CICN to plot? */ { PlotCIcon(&icon_rect,icon_handle); /* Yup...Do it */ DisposCIcon(icon_handle); } else { icon_handle=GetResource('ICON',which_icon+256); /* Nope...Get a normal Icon */ if(icon_handle!=NULL) { PlotIcon(&icon_rect,icon_handle); } } MoveTo(control_rectangle.left+space_on_left+ICON_SPACE,(control_rectangle.top+control_rectangle.bottom+font_info.ascent-font_info.descent)/2);/* Move to where Text should be drawn */ space_for_string-=ICON_SPACE; } break; } } else { MoveTo(control_rectangle.left+space_on_left,(control_rectangle.top+control_rectangle.bottom+font_info.ascent-font_info.descent)/2-1);/* Move to where Text should be drawn */ } TextFace(item_style); shrink_string((char *) ¤t_selection_text[0],space_for_string); /* Shrink the text for the item if it doesn't fit (c/o JS!) */ DrawString(current_selection_text); /* Draw the Text */ if(!active) /* If Inactive - Dim it */ { gray_out_rectangle(&control_rectangle); /* Dim it by graying it */ } if(color_qd_implemented&&have_item_color) /* Color QD? */ { RGBForeColor(&foreground_color); /* Restore the original foreground color */ RGBBackColor(&background_color); /* Restore the original background color */ } } return(0l); } long test_control(short control_type,ControlHandle the_control,long parameter) { Point hit_point; Rect title_rect; Rect control_rectangle; short titled; short new_style; short ball_check_char; short use_window_font; hit_point.v=HiWord(parameter); /* Get the Hit point from the parameter */ hit_point.h=LoWord(parameter); titled=control_type&TITLED_MASK; /* Is there a title? */ new_style=control_type&NEW_STYLE_MASK; /* Is it a new style pop up? */ ball_check_char=control_type&CHECK_MASK; /* Use the '•' check char? */ use_window_font=control_type&useWFont; /* Use the Window's Font? */ if((**the_control).contrlHilite==INACTIVE) /* Is the control inactive? */ { return(0l); /* Yes -return 0 */ } else { calculate_rectangles(the_control,titled,new_style,use_window_font,&title_rect,&control_rectangle); if(PtInRect(hit_point,&control_rectangle)) /* Is the point in our control? */ { return(IN_MENU); /* Yes - Point is in our control */ } } return(0l); /* Point is not in our control! */ } long calculate_control_region(short control_type,ControlHandle the_control,long parameter) { short part; Rect indicator_rect; RectRgn((RgnHandle)parameter,&(**the_control).contrlRect); /* Set the Region */ return(0l); } long initialize_control(short control_type,ControlHandle the_control,long parameter) { pop_up_data_handle data_handle; (**the_control).contrlData=NewHandle(sizeof(pop_up_data_struct)); /* Allocate space for out struct */ if((**the_control).contrlData!=NULL) /* Were we were able to allocate it? */ { HLock((**the_control).contrlData); /* Lock the handle */ data_handle=(pop_up_data_handle)(**the_control).contrlData; /* For easier referencing */ if((**the_control).contrlRfCon!=0) /* Resource Based Menu?? */ { (**data_handle).type=TRUE; /* Yes - store a flag */ SetResLoad(FALSE); (**data_handle).the_menu=(MenuHandle)GetResource('MENU',(**the_control).contrlRfCon); /* Is menu already loaded? */ SetResLoad(TRUE); if(*(**data_handle).the_menu==NULL) /* Is it a handle to a NULL resource? */ { ReleaseResource((**data_handle).the_menu); /* Yup...Release the Resource */ (**data_handle).we_loaded_the_menu=TRUE; /* We loaded this bad boy with GetMenu! */ (**data_handle).the_menu=GetMenu(LoWord((**the_control).contrlRfCon)); /* Get the Menu */ } else { (**data_handle).we_loaded_the_menu=FALSE; /* Did not load this-calling application is responsible */ } } else /* Dynaminc Menu */ { (**data_handle).type=FALSE; /* No - store a flag */ (**data_handle).we_loaded_the_menu=FALSE; /* We did not load the menu */ (**data_handle).the_menu=NULL; /* MenuHandle will be put in contrlRfCon by application */ } HUnlock((**the_control).contrlData); /* Unlock the Handle */ } adjust_max_and_min(the_control); /* After Initializing, adjust the Max and Min */ (**the_control).contrlAction = (ProcPtr) -1; /* 1.3.2-Require use of AutoTrack */ return(0l); } long dispose_control(short control_type,ControlHandle the_control,long parameter) { if((**the_control).contrlData!=NULL) /* We allocated a Handle */ { if((**(pop_up_data_handle)(**the_control).contrlData).type) { /* MenuHandle is in the_menu */ if((**(pop_up_data_handle)(**the_control).contrlData).we_loaded_the_menu) /* If we loaded the menu (GetMenu) */ { ReleaseResource((**(pop_up_data_handle)(**the_control).contrlData).the_menu); /* we are responsible for releasing it */ } } else /* MenuHandle is in contrlRfCon - Application must dispose of it */ { } DisposHandle((**the_control).contrlData); /* Get rid of handle we allocated */ (**the_control).contrlData=NULL; /* Set the data pointer to NULL (not needed, but good cleanup) */ } return(0l); } long position_control(short control_type,ControlHandle the_control,long parameter) { return(0l); } long thumb_control(short control_type,ControlHandle the_control,long parameter) { return(0l); } long drag_control(short control_type,ControlHandle the_control,long parameter) { return(1l); } long auto_track_control(short control_type,ControlHandle the_control,long parameter) { Point pop_up_point; short current_selection; short new_choice; long chosen; MenuHandle the_menu; Rect title_rect; Rect control_rectangle; short titled; short new_style; short ball_check_char; short use_window_font; Handle mctb_handle; short nEntries; short color_qd_implemented; the_menu=get_pop_menu(the_control); /* Get the Menu Handle */ color_qd_implemented=check_color(); if(the_menu==NULL) /* If no menu has been declared, we can't pop it up */ { return(1l); /* Let Control Manager know that we dragged the control */ } InsertMenu(the_menu,-1); /* Insert the Menu Into the Menu List */ titled=control_type&TITLED_MASK; /* Titled Menu??? */ new_style=control_type&NEW_STYLE_MASK; /* New Style Pop Up? */ ball_check_char=control_type&CHECK_MASK; /* Use the '•' check char? */ use_window_font=control_type&useWFont; /* Use the Window's Font? */ calculate_rectangles(the_control,titled,new_style,use_window_font,&title_rect,&control_rectangle); pop_up_point.v=control_rectangle.top; /* Calculate the Pop Up point */ pop_up_point.h=control_rectangle.left; if(titled) /* Titled Menu??? */ { InvertRect(&title_rect); /* Invert the Title as per Mac User Interface Guidelines */ } LocalToGlobal(&pop_up_point); /* Convert the Point to Global for Menu Manager */ current_selection=(**the_control).contrlValue; /* Get the Selected Item from contrlValue */ if(ball_check_char) /* Use the '•' as the check character? (My personal Favorite-CF) */ { SetItemMark(the_menu,current_selection,'•'); /* Yes - Do it! */ } else { SetItemMark(the_menu,current_selection,(char) 18); /* No - Use the Check Mark */ } CalcMenuSize(the_menu); /* We must perform this initially */ trap_calc_menu_size(TRUE); /* Redefine the CalcMenuSize trap to our dummy routine (1.4b2) */ if((control_rectangle.right-control_rectangle.left)>(**the_menu).menuWidth) /* Is the width we are using greater than the actual menuWidth? (because of triangle) (1.4b2) */ { (**the_menu).menuWidth=control_rectangle.right-control_rectangle.left; /* Yup. Adjust the width that we will pop up (1.4b2) */ } RememberA4(); /* Remember this so our trap of CalcMenuSize can use globals */ pop_up_menu_width=(**the_menu).menuWidth; /* Store this for use by our CalcMenuSize trap code */ chosen=PopUpMenuSelect(the_menu,pop_up_point.v,pop_up_point.h,current_selection); /* Pop It Up (Dude!) */ trap_calc_menu_size(FALSE); /* Restore the correct CalcMenuSize trap */ if(titled) /* Titled Menu??? */ { InvertRect(&title_rect); /* Invert the Title as per Mac User Interface Guidelines */ } SetItemMark(the_menu,current_selection,' '); /* Remove the Mark */ DeleteMenu((**the_menu).menuID); /* Remove the Menu from the Menu List (Corrected in 1.3.2 THNX JS!) */ /* This code thanks to Doug McKenna: */ /* (Also thanks to Jeremy Grodberg) */ if (color_qd_implemented) { mctb_handle=Get1Resource('mctb',(**the_menu).menuID); /* Get a handle to the resource */ if(mctb_handle!=NULL) /* Is the Handle OK? */ { nEntries=(GetHandleSize(mctb_handle)-sizeof(short))/sizeof(MCEntry); /* Calculate the number of entries */ HLock(mctb_handle); /* Lock the Handle */ SetMCEntries(nEntries, (MCTablePtr)((*(char **)mctb_handle)+sizeof(short))); /* Set the entries in the table */ HUnlock(mctb_handle); /* Unlock the Handle */ ReleaseResource(mctb_handle); /* Release the Resource */ } } if(HiWord(chosen)!=0) /* Did the user choose anything in the menu?? */ { new_choice=LoWord(chosen); /* Yes, get which item */ if(new_choice!=current_selection) /* Different than the current one?? */ { (**the_control).contrlValue=new_choice; /* Yes, Store the new choice */ InsetRect(&control_rectangle,-1,-1); /* Now form a rectangle to be erased, because the height can change */ control_rectangle.bottom+=1; control_rectangle.right+=1; EraseRect(&control_rectangle); /* Erase it. */ return(1l); } return(0l); /* We popped it, but did not change the value! */ } return(0l); /* User did not make a choice */ } draw_pop_up_symbol(short h,short v) /* Draw the downward pointing triangle for new styled pop ups */ { short loop; for(loop=0;loop<6;++loop) /* Loop through the six lines of the triangle */ { MoveTo(h+loop-6,v+loop); /* Move to beginning of each line */ Line(10-(loop*2),0); /* Draw line of appropriate length */ } } save_pen_font(ControlHandle the_control,pen_font_struct *save_struct) { GetPenState(&(*save_struct).save_pen); (*save_struct).save_font=(*(**the_control).contrlOwner).txFont; /* Save off the font */ (*save_struct).save_size=(*(**the_control).contrlOwner).txSize; /* Save off the size */ (*save_struct).save_face=(*(**the_control).contrlOwner).txFace; /* Save off the style */ } set_pen_font(pen_font_struct *save_struct) { SetPenState(&(*save_struct).save_pen); TextFont((*save_struct).save_font); /* Restore the font */ TextSize((*save_struct).save_size); /* Restore the size */ TextFace((*save_struct).save_face); /* Restore the style */ } calculate_rectangles(ControlHandle the_control,short titled,short new_style,short use_window_font,Rect *title_rect,Rect *control_rectangle) { MenuHandle the_menu; pop_up_data_handle data_handle; short command_char; short which_icon; short menu_height; HLock((**the_control).contrlData); /* Lock the control data area */ data_handle=(pop_up_data_handle)(**the_control).contrlData; /* Set our own formatted handle to it */ the_menu=get_pop_menu(the_control); /* Get a handle to the menu we are dealing with */ if(the_menu==NULL) /* Did we not get a menu? */ { menu_height=NORMAL_MENU_SIZE; /* Did not get menu. Set height to normal menu item height */ } else /* We did get a menu. */ { CalcMenuSize(the_menu); /* Calculate the menu size */ GetItemCmd(the_menu,(**the_control).contrlValue,&command_char); /* Get the command char to determine if we have a sicn, etc.*/ switch(command_char) { case SICN_MENU: menu_height=SICN_MENU_SIZE; break; case RICN_MENU: menu_height=SICN_MENU_SIZE; break; default: GetItemIcon(the_menu,(**the_control).contrlValue,&which_icon); if(which_icon==0) { menu_height=NORMAL_MENU_SIZE; } else { menu_height=ICON_MENU_SIZE; } break; } } if(titled) /* Calculate Rectangles for Titled Menus: */ { if(use_window_font) /* Are we to use the window font?? */ { TextFont((*(**the_control).contrlOwner).txFont); /* Yep. Get the font */ TextSize((*(**the_control).contrlOwner).txSize); /* Get the font size */ TextFace((*(**the_control).contrlOwner).txFace); /* Get the window's Face */ } else /* Nope. */ { TextFont(0); /* Use the System Font */ TextSize(0); /* Use the System Point Size */ TextFace(0); /* No Text Face */ } (*title_rect).top=((**the_control).contrlRect.top+(**the_control).contrlRect.bottom)/2-8; (*title_rect).left=(**the_control).contrlRect.left; (*title_rect).bottom=(*title_rect).top+16; (*title_rect).right=(*title_rect).left+StringWidth((**the_control).contrlTitle)+3; /* Changed from +1 to keep title moved slightly from the menu item */ (*control_rectangle).left=(*title_rect).right+1; /* Changed from +3 to remove space between title rect and menu item (JS) */ (*control_rectangle).top=((**the_control).contrlRect.top+(**the_control).contrlRect.bottom-menu_height)/2; (*control_rectangle).bottom=(*control_rectangle).top+menu_height; if(the_menu!=NULL) { (*control_rectangle).right=(*control_rectangle).left+(**the_menu).menuWidth; if(new_style) /* New style of pop up? */ { (*control_rectangle).right+=EXTRA_SPACE_FOR_NEW_STYLE; /* Yup. Now that we can pop up a menu of any size, go ahead and add space */ } } else { /* No Menu has been declared! */ (*control_rectangle).right=(**the_control).contrlRect.right; /* Empty menu is displayed as large as the control rectangle (JS) */ } } else /* Calculate Rectangles for Untitled Menus: */ { (*control_rectangle).top=((**the_control).contrlRect.top+(**the_control).contrlRect.bottom-menu_height)/2; (*control_rectangle).bottom=(*control_rectangle).top+menu_height; (*control_rectangle).left=(**the_control).contrlRect.left; if(the_menu!=NULL) { (*control_rectangle).right=(*control_rectangle).left+(**the_menu).menuWidth; if(new_style) /* New style of pop up? */ { (*control_rectangle).right+=EXTRA_SPACE_FOR_NEW_STYLE; /* Yup. Now that we can pop up a menu of any size, go ahead and add space */ } } else { /* No Menu has been declared! */ (*control_rectangle).right=(**the_control).contrlRect.right; /* Empty menu is displayed as large as the control rectangle (JS) */ } } if((*control_rectangle).right>(**the_control).contrlRect.right) /* (1.4-c/o JS) The control rectangle will not be made larger than */ { /* the contrlRect specified. Instead the item text will be shrunk. */ (*control_rectangle).right=(**the_control).contrlRect.right; } HUnlock((**the_control).contrlData); /* Unlock the contrlData Handle */ } gray_out_rectangle(Rect *the_rectangle) { Pattern dim_pattern; StuffHex(&dim_pattern,"\pAA55AA55AA55AA55"); /* Grey Pattern */ PenPat(dim_pattern); /* Set the Pen to the Pattern */ PenMode(patBic); /* Set the Pen Mode */ InsetRect(the_rectangle,1,1); /* Do not want to dim the Frame */ PaintRect(the_rectangle); /* Dim it */ } MenuHandle get_pop_menu(ControlHandle the_control) /* Return the menu of the control */ { if((**(pop_up_data_handle)(**the_control).contrlData).type==TRUE) /* Is it in the data structure? */ { /* Menu is in pop_up_data_handle */ /* Yes */ return((MenuHandle)(**(pop_up_data_handle)(**the_control).contrlData).the_menu); /* Return the menu */ } else /* No, User should have placed it in contrlRfCon */ { /* Menu Handle is in contrlRfCon */ return((MenuHandle)(**the_control).contrlRfCon); /* Return the menu */ } } plot_sicn(ControlHandle the_control,short h,short v,short which_sicn) { BitMap src_bits; SICNHand the_sicn; Rect the_rect; the_sicn=(SICNHand)GetResource('SICN',which_sicn+256); /* Get the SICN Resource (+256 because you must subtract 256 when you put */ if(the_sicn!=NULL) /* it in the menu structure. Macintosh Technical Note #253 */ { HLock(the_sicn); /* Lock it up! */ if(GetHandleSize(the_sicn)<sizeof(SICN)) /* Check the size of the resource */ { /* This should NEVER happen. It means that the SICN resource was */ /* less than the required size, so do not attempt to plot it! */ } else { /* This code is care of Macintosh Technical Note #252 */ src_bits.baseAddr=(Ptr)(*the_sicn)[0]; src_bits.rowBytes=2; SetRect(&src_bits.bounds,0,0,16,16); SetRect(&the_rect,h,v,h+16,v+16); CopyBits(&src_bits,&(*(**the_control).contrlOwner).portBits,&src_bits.bounds,&the_rect,srcCopy,NULL); } HUnlock(the_sicn); } } adjust_max_and_min(ControlHandle the_control) { MenuHandle the_menu; the_menu=get_pop_menu(the_control); /* Get the menu Handle */ if(the_menu!=NULL) /* Did we get one? */ { (**the_control).contrlMin=1; /* Yes - Menu's lowest value is always 1 */ (**the_control).contrlMax=CountMItems(the_menu); /* Max value is number of items */ } else /* No - No Menu Set Default values */ { (**the_control).contrlMin=1; /* Min Defaults to 1 */ (**the_control).contrlMax=1; /* Max Defaults to 1 */ } } void shrink_string(char *s, short space_for_string) { short s_pix; short s_len; if (space_for_string<=0) /* Do we have any space for string? */ { space_for_string=0; /* No. */ s[0]='\0'; /* Make string an empty string */ } s_pix = StringWidth(s); if (s_pix > space_for_string) { s_len = s[0]; space_for_string -= CharWidth('…'); if(space_for_string<=0) { space_for_string=0; s[0]='\0'; } else { for(s_len = s[0]; s_len && s_pix >= space_for_string; --s_len) { s_pix -= CharWidth(s[s_len]); } ++s_len; s[s_len] = '…'; s[0] = (unsigned char) s_len; } } } pascal void new_calc_menu_size(MenuHandle the_menu) { long save_d1; /* The object of this routine is to be a dummy to replace */ /* CalcMenuSize when PopUpMenuSelect calls it. This will */ /* call the real CalcMenuSize, but replace the menuWidth */ /* calculated with the one we actually want. This will */ /* allow the CDEF to “pop-up” a larger menu. (i.e. with */ /* space for the downward pointing triangle) This seems */ /* to be a better approach then crunching the text in, or */ /* re-writing PopUpMenuSelect (no thanks). */ asm { move.l d1,save_d1 ; Save the D1 register } SetUpA4(); /* Restore the A4 world so we can use our globals */ CallPascal(the_menu,real_calc_menu_size); /* Call the real CalcMenuSize */ (**the_menu).menuWidth=pop_up_menu_width; /* Replace the menuWidth with our value */ RestoreA4(); /* Restore the A4 world */ asm { move.l save_d1,d1 ; Restore the D1 register } } trap_calc_menu_size(short remove) { if(remove) /* Are we installing our dummy routine?? */ { real_calc_menu_size=(void *)GetTrapAddress(0x148); /* Yup. Get the old trap address */ SetTrapAddress((void *)new_calc_menu_size,0x148); /* Install the new one. */ } else /* Nope. We are restoring the old address */ { SetTrapAddress(real_calc_menu_size,0x148); /* So do it. */ } } void convert_rectangle(Rect *conversion_rectangle,short to_global) { Point conversion_point; conversion_point.v=(*conversion_rectangle).top; /* This converts a rectangle from local to global coords */ conversion_point.h=(*conversion_rectangle).left; if(to_global) { LocalToGlobal(&conversion_point); } else { GlobalToLocal(&conversion_point); } (*conversion_rectangle).top=conversion_point.v; (*conversion_rectangle).left=conversion_point.h; conversion_point.v=(*conversion_rectangle).bottom; conversion_point.h=(*conversion_rectangle).right; if(to_global) { LocalToGlobal(&conversion_point); } else { GlobalToLocal(&conversion_point); } (*conversion_rectangle).bottom=conversion_point.v; (*conversion_rectangle).right=conversion_point.h; } check_color() { SysEnvRec the_environment; /* Environment record to determine if Color QD is implemented */ SysEnvirons(1,&the_environment); /* Have machine tell us the environment */ if(the_environment.hasColorQD) /* Color QD available? */ { return(TRUE); /* Yup. */ } else { return(FALSE); /* Nope. */ } }